use
strict
qw(subs vars)
;
no
warnings;
use
5.010;
BEGIN {
$HTML::Microformats::DocumentContext::AUTHORITY
=
'cpan:TOBYINK'
;
$HTML::Microformats::DocumentContext::VERSION
=
'0.105'
;
}
sub
new
{
my
(
$class
,
$document
,
$uri
,
$cache
) =
@_
;
$cache
||= HTML::Microformats::ObjectCache->new;
my
$self
= {
'document'
=>
$document
,
'uri'
=>
$uri
,
'profiles'
=> [] ,
'cache'
=>
$cache
,
};
bless
$self
,
$class
;
foreach
my
$e
(
$document
->getElementsByTagName(
'*'
))
{
my
$np
=
$e
->nodePath;
$np
=~ s?\*/?\*\[1\]/?g;
$e
->setAttribute(
'data-cpan-html-microformats-nodepath'
,
$np
)
}
(
$self
->{
'bnode_prefix'
} = Data::UUID->new->create_hex) =~ s/^0x//;
$self
->_process_langs(
$document
->documentElement);
$self
->_detect_profiles;
return
$self
;
}
sub
cache
{
return
$_
[0]->{
'cache'
};
}
sub
document
{
return
$_
[0]->{
'document'
};
}
sub
uri
{
my
$this
=
shift
;
my
$param
=
shift
||
''
;
my
$opts
=
shift
|| {};
if
((
ref
$opts
) =~ /^XML::LibXML/)
{
my
$x
= {
'element'
=>
$opts
};
$opts
=
$x
;
}
if
(
$param
=~ /^([a-z][a-z0-9\+\.\-]*)\:/i)
{
return
$param
;
}
elsif
(
$opts
->{
'require-absolute'
})
{
return
undef
;
}
my
$base
=
$this
->{
'uri'
};
if
(
$opts
->{
'element'
})
{
$base
=
$this
->get_node_base(
$opts
->{
'element'
});
}
my
$rv
= URI->new_abs(
$param
,
$base
)->canonical->as_string;
while
(
$rv
=~ m!^(http://.*)(\.\./|\.)+(\.\.|\.)?$!i)
{
$rv
= $1;
}
return
$rv
;
}
sub
document_uri
{
my
$self
=
shift
;
return
$self
->{
'document_uri'
} ||
$self
->uri;
}
sub
make_bnode
{
my
(
$self
,
$elem
) =
@_
;
return
sprintf
(
'_:B%s%04d'
,
$self
->{
'bnode_prefix'
},
$self
->{
'next_bnode'
}++);
}
sub
profiles
{
return
@{
$_
[0]->{
'profiles'
} };
}
sub
has_profile
{
my
$self
=
shift
;
foreach
my
$requested
(
@_
)
{
foreach
my
$available
(
$self
->profiles)
{
return
1
if
$available
eq
$requested
;
}
}
return
0;
}
sub
add_profile
{
my
$self
=
shift
;
foreach
my
$p
(
@_
)
{
push
@{
$self
->{
'profiles'
} },
$p
unless
$self
->has_profile(
$p
);
}
}
sub
representative_hcard
{
my
$self
=
shift
;
unless
(
$self
->{
'representative_hcard'
})
{
my
@hcards
= HTML::Microformats::Format::hCard->extract_all(
$self
->document->documentElement,
$self
);
HCARD:
foreach
my
$hc
(
@hcards
)
{
next
unless
ref
$hc
;
if
(
defined
$hc
->data->{
'uid'
}
and
$hc
->data->{
'uid'
} eq
$self
->document_uri)
{
$self
->{
'representative_hcard'
} =
$hc
;
last
HCARD;
}
}
unless
(
$self
->{
'representative_hcard'
})
{
HCARD:
foreach
my
$hc
(
@hcards
)
{
next
unless
ref
$hc
;
if
(
$hc
->data->{
'_has_relme'
})
{
$self
->{
'representative_hcard'
} =
$hc
;
last
HCARD;
}
}
}
if
(
$self
->{
'representative_hcard'
})
{
$self
->{
'representative_hcard'
}->{
'representative'
} = 1;
}
}
return
$self
->{
'representative_hcard'
};
}
sub
representative_person_id
{
my
$self
=
shift
;
my
$as_trine
=
shift
;
my
$hcard
=
$self
->representative_hcard;
if
(
$hcard
)
{
return
$hcard
->id(
$as_trine
,
'holder'
);
}
unless
(
defined
$self
->{
'representative_person_id'
})
{
$self
->{
'representative_person_id'
} =
$self
->make_bnode;
}
if
(
$as_trine
)
{
return
(
$self
->{
'representative_person_id'
} =~ /^_:(.*)$/) ?
RDF::Trine::Node::Blank->new($1) :
RDF::Trine::Node::Resource->new(
$self
->{
'representative_person_id'
});
}
return
$self
->{
'representative_person_id'
};
}
sub
contact_hcard
{
my
$self
=
shift
;
unless
(
$self
->{
'contact_hcard'
})
{
my
@hcards
= HTML::Microformats::Format::hCard->extract_all(
$self
->document->documentElement,
$self
);
my
(
$shallowest
,
$shallowest_depth
);
HCARD:
foreach
my
$hc
(
@hcards
)
{
next
unless
ref
$hc
;
my
$address
= searchAncestorTag(
'address'
,
$hc
->element);
next
unless
defined
$address
;
my
@bits
=
split
m
'/'
,
$address
;
my
$address_depth
=
scalar
(
@bits
);
if
(
$address_depth
<
$shallowest_depth
|| !
defined
$shallowest
)
{
$shallowest_depth
=
$address_depth
;
$shallowest
=
$hc
;
}
}
$self
->{
'contact_hcard'
} =
$shallowest
;
if
(
$self
->{
'contact_hcard'
})
{
$self
->{
'contact_hcard'
}->{
'contact'
} = 1;
}
}
return
$self
->{
'contact_hcard'
};
}
sub
contact_person_id
{
my
$self
=
shift
;
my
$as_trine
=
shift
;
my
$hcard
=
$self
->contact_hcard;
if
(
$hcard
)
{
return
$hcard
->id(
$as_trine
,
'holder'
);
}
unless
(
defined
$self
->{
'contact_person_id'
})
{
$self
->{
'contact_person_id'
} =
$self
->make_bnode;
}
if
(
$as_trine
)
{
return
(
$self
->{
'contact_person_id'
} =~ /^_:(.*)$/) ?
RDF::Trine::Node::Blank->new($1) :
RDF::Trine::Node::Resource->new(
$self
->{
'contact_person_id'
});
}
return
$self
->{
'contact_person_id'
};
}
sub
_process_langs
{
my
$self
=
shift
;
my
$elem
=
shift
;
my
$lang
=
shift
;
if
(
$elem
->hasAttributeNS(XML_XML_NS,
'lang'
))
{
$lang
=
$elem
->getAttributeNS(XML_XML_NS,
'lang'
);
}
elsif
(
$elem
->hasAttribute(
'lang'
))
{
$lang
=
$elem
->getAttribute(
'lang'
);
}
$elem
->setAttribute(
'data-cpan-html-microformats-lang'
,
$lang
);
foreach
my
$child
(
$elem
->getChildrenByTagName(
'*'
))
{
$self
->_process_langs(
$child
,
$lang
);
}
}
sub
_detect_profiles
{
my
$self
=
shift
;
{
if
(
$head
->hasAttribute(
'profile'
))
{
my
@p
=
split
/\s+/,
$head
->getAttribute(
'profile'
);
foreach
my
$p
(
@p
)
{
$self
->add_profile(
$p
)
if
length
$p
;
}
}
}
}
1;